//
// Created by baigui on 21-7-4.
//

#include "NDKDecoder.h"
//#include "typeinfo"
#include "NDKRender.h"
#include "MediaPlayer.h"
#include "VideoDecoder.h"
#define TAG "NDKDecoder"
NDKDecoder::NDKDecoder(weak_ptr<MediaPlayer> player) : VideoDecoder(player) {

}

bool NDKDecoder::Open(void* codec) {

    if (!mPlayer.lock()->LoadRender(NDKCodecType)){
        LOGD("open ndk decoder render err");
        return false;
    }
    VideoRender *render = mPlayer.lock()->getVideoRender();
    if (render == nullptr)
        return false;


    auto *stream = (MediaStream*)codec;
    LOGD("open ndk decoder %s",stream->mime);

    char *buf = new char[strlen(stream->mime)+1];
    strcpy(buf, stream->mime);

    NDK_codec = AMediaCodec_createDecoderByType(buf);
    LOGD("open ndk decoder %s",buf);
    AMediaFormat *format = AMediaFormat_new();


//    AMediaFormat_setInt32(format, "encoder", 0);
//
//    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, 0);

    AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, buf);

    if (stream->type == video)
    {
        AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, stream->video.width);
        AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, stream->video.height);
//        AMediaFormat_setInt32(format, "rotation-degrees", p_args->video.i_angle);
//        if (p_args->video.p_surface)
//        {
//            p_anw = p_args->video.p_surface;
//            if (p_args->video.b_tunneled_playback)
//                AMediaFormat_setInt32(format,
//                                           "feature-tunneled-playback", 1);
//            if (p_args->video.b_adaptive_playback)
//                AMediaFormat_setInt32(format,
//                                           "feature-adaptive-playback", 1);
//        }
    }
    else
    {
//        AMediaFormat_setInt32(format, "sample-rate", p_args->audio.i_sample_rate);
//        AMediaFormat_setInt32(format, "channel-count", p_args->audio.i_channel_count);
    }

    ANativeWindow* su = ((NDKRender*)render)->getSurface();


    if (AMediaCodec_configure(NDK_codec, format, su, NULL, 0) != AMEDIA_OK){
        LOGE("config ndkcodec wrong!!");
        return false;
    }
//
    if(AMediaCodec_start(NDK_codec) == AMEDIA_OK){
        LOGV("start ndkcodec sucess!!");
        return true;
    } else{
        LOGE("start ndkcodec wrong!!");
        return false;
    }
}

void NDKDecoder::requestPicture() {
}

bool NDKDecoder::start() {
    VideoDecoder::start();
    LOGV("start ndkcodec start sucess!!");
    mOutLooper = make_shared<Looper>(shared_from_this());
    mOutLooper->post(DECODER_DEQUEUE_OUTPUT, nullptr,200);
    *a = 1;
    mLooper->post(DECODER_QUEUE_BUFFER, a, 200);
    LOGV("start ndkcodec start sucess end!!");
    return true;
}

void NDKDecoder::handle(int what, void *data) {

//    LOGV("handle the decoder !");
    if(what == DECODER_QUEUE_BUFFER){

        if (data != nullptr){
            mLooper->post(DECODER_QUEUE_BUFFER, a, 2);
        }

        size_t i_mc_size = 0;

        int idx = AMediaCodec_dequeueInputBuffer(NDK_codec,20000);
        if(idx < 0){
            LOGV("AMediaCodec_dequeueInputBuffer Err");
            return;
        }
        block_t *p = blockFifo->get();
        if(!p)
            return;

        auto buf = AMediaCodec_getInputBuffer(NDK_codec,idx,&i_mc_size);

        if (!buf) {
            LOGV("AMediaCodec_getInputBuffer Err : %ld",i_mc_size);
            return ;
        }

        int picture_size = p->getDataSize() - p->getDataStart();
        if(picture_size < i_mc_size){
            i_mc_size = picture_size;
            memcpy(buf, p->getbuffer() + p->getDataStart(), i_mc_size);
            delete (blockFifo->popFirst());
        } else{
            LOGE("rare happen!!!");
            memcpy(buf, p->getbuffer() + p->getDataStart(), i_mc_size);
            p->setDataStart(p->getDataStart() + i_mc_size);
        }

        int ret = AMediaCodec_queueInputBuffer(NDK_codec,idx,p->getDataStart(),i_mc_size,20000,0);
        LOGV("AMediaCodec_queueInputBuffer sucess return: %d  size : %ld ",ret, i_mc_size);

    } else if(what == DECODER_DEQUEUE_OUTPUT){

        AMediaCodecBufferInfo info;
        auto status = AMediaCodec_dequeueOutputBuffer(NDK_codec, &info, 0);
        if (status >= 0) {

            if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
                LOGV("output EOS");
            }
            int64_t presentation = info.presentationTimeUs;
            if (renderstart < 0) {
                renderstart = mdate() - presentation;
            }
            int64_t delay = mdate() - (renderstart + presentation);

            int ret = AMediaCodec_releaseOutputBuffer(NDK_codec, status, info.size != 0);
            LOGV("AMediaCodec_releaseOutputBuffer sucess ret: %d ---%ld",ret , info.presentationTimeUs);
            mOutLooper->post(DECODER_DEQUEUE_OUTPUT, nullptr,40);
            return;

        } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
            LOGV("output buffers changed");
        } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
            auto format = AMediaCodec_getOutputFormat(NDK_codec);
            LOGV("format changed to: %s", AMediaFormat_toString(format));
            AMediaFormat_delete(format);
        } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
            LOGV("no output buffer right now");
        } else {
            LOGV("unexpected info code: %zd", status);
        }
        mOutLooper->post(DECODER_DEQUEUE_OUTPUT, nullptr,40);
    }

}

void NDKDecoder::QueueBuffer(block_t *p){
    if (blockFifo != nullptr && p != nullptr)
        blockFifo->add(p);

//    mLooper->post(DECODER_QUEUE_BUFFER, nullptr,0);
}


NDKDecoder::~NDKDecoder() = default;
